# coding: utf-8
# Author: Legend奇
# @Time： 2020/7/24 上午10:25
import copy
import json
import re

from fastapi import APIRouter, HTTPException, Request
from starlette.responses import JSONResponse
from starlette.status import HTTP_400_BAD_REQUEST
from tortoise.exceptions import MultipleObjectsReturned, DoesNotExist

import settings
from apps.iacs.models import User, PermissionGroup, Menu, Api
from apps.iacs.serializers.user_serializer import UserSchema, MenuSchema, PermissionGroupSchema
from apps.log.models import OperationLog
from apps.log.operations import C_SIGN_IN, C_USER, C_CREATE, C_UPGRADE, C_EXECUTE
from base.constant import PermissionGroupType
from utils.decorator import action_name
from utils.encryption import make_token, cal_sha1_string
from utils.redis import Redis
from utils.time import get_current_time_by_microsecond

user_router = APIRouter()


@action_name('用户登录', user_default=True)
@user_router.post('/iacs/user/login', )
async def login(request: Request):
    data = await request.body()
    data = json.loads(data.decode())
    username = data.get("username")
    password = data.get("password")
    password = cal_sha1_string(password)
    try:
        user = await User.get(username=username)
    except DoesNotExist:
        raise HTTPException(HTTP_400_BAD_REQUEST, '用户不存在')
    except MultipleObjectsReturned:
        raise HTTPException(HTTP_400_BAD_REQUEST, '错误的用户, 用户名重复')
    if not user.password == password:
        raise HTTPException(HTTP_400_BAD_REQUEST, '密码错误')
    token = make_token()
    login_token_key = settings.REDIS_LOGIN_TOKEN_KEY.format(token=token)
    login_user_key = settings.REDIS_LOGIN_USER_KEY.format(user_id=user.id)
    data = {
        'id': user.id,
        'username': user.username,
        'token': token,
        'client_host': request.client.host,
        'create_timestamp': get_current_time_by_microsecond()
    }
    async with Redis() as redis:
        await redis.hmset_dict(login_token_key, data)
        permisson_group = await user.permission_group
        await redis.expire(login_user_key, permisson_group.auth_time)
    # 记录操作日志
    await OperationLog(**{
        'username': user.username,
        'op_type': C_SIGN_IN,
        'op_sort': C_USER,
        'desc': '登入系统'
    }).save()
    return JSONResponse({'token': token, 'msg': '认证成功'})


@action_name('创建用户')
@user_router.post('/iacs/user', )
async def create(request: Request):
    email_re = re.compile(r'^\w+@(\w+\.)+(com|cn|net|edu)$')
    number_re = re.compile(r'^1[3-9]\d{9}$')
    data = await request.body()
    data = json.loads(data.decode())
    username = data.get("username")
    alias = data.get('alias')
    cellphone_number = data.get('cellphone_number')
    email = data.get('email')
    permission_group = data.get('permission_group')
    password = data.get('password')
    if not email_re.search(email):
        raise HTTPException(HTTP_400_BAD_REQUEST, '邮箱不正确')
    if not number_re.search(cellphone_number):
        raise HTTPException(HTTP_400_BAD_REQUEST, '手机号码不正确')
    if User.exists(username=username):
        raise HTTPException(HTTP_400_BAD_REQUEST, '用户已存在')
    else:
        new_user = User(**{
            'username': username,
            'alias': alias,
            'cellphone_number': cellphone_number,
            'email': email,
            'permission_group': await PermissionGroup.get(id=permission_group),
            'password': cal_sha1_string(password)
        })
        if new_user.check():
            await new_user.save()
        # 记录操作日志
        await OperationLog(**{
            'op_type': C_CREATE,
            'op_sort': C_USER,
            'desc': '创建新用户',
            'data': {
                'after': await UserSchema.from_tortoise_orm(new_user)
            }
        }).save()
    return JSONResponse({'msg': '用户创建成功'})


@action_name('删除用户')
@user_router.delete('/iacs/user/', )
async def destory(request: Request):
    data = await request.body()
    form = await request.form()
    print(data)
    print(form)


@action_name('获取当前用户认证状态', user_default=True)
@user_router.get('/iacs/user/is_authenticated', )
async def is_authenticated(request: Request):
    return JSONResponse({'status': 'success'})


@action_name('获取当前用户信息', user_default=True)
@user_router.get('/iacs/user/info', response_model=UserSchema, )
async def info(request: Request):
    # data = await UserSchema.from_tortoise_orm(request.user)
    # print('#################', data.dict())
    return await UserSchema.from_tortoise_orm(request.user)


@action_name('注销用户登录', user_default=True)
@user_router.get('/iacs/user/sign_out', )
async def sign_out(request: Request):
    auth_token = request.headers["Authorization"].split('Token ')[1]
    async with Redis() as redis:
        await redis.delete(settings.REDIS_LOGIN_TOKEN_KEY.format(token=auth_token))
        await redis.delete(settings.REDIS_LOGIN_USER_KEY.format(user_id=request.user.id))
    return JSONResponse({'status': 'success'})


@action_name('修改当前用户密码', user_default=True)
@user_router.post('/iacs/user/change_pwd', )
async def change_pwd(request: Request):
    user = request.user
    data = await request.body()
    data = json.loads(data.decode())
    password = data.get("password")
    new_password = data.get("newPassword")
    if not password:
        raise HTTPException(HTTP_400_BAD_REQUEST, '密码不能为空')
    password = cal_sha1_string(password)
    if not cal_sha1_string(password) == user.password:
        raise HTTPException(HTTP_400_BAD_REQUEST, '密码校验失败，请重新输入')
    user.password = cal_sha1_string(new_password)
    await user.save()
    await OperationLog(**{
        'op_type': C_UPGRADE,
        'op_sort': C_USER,
        'desc': '修改密码'
    }).save()
    return JSONResponse({'status': 'success'})


@action_name('修改当前用户信息')
@user_router.post('/iacs/user/change_info', response_model=UserSchema)
async def change_info(request: Request):
    data = await request.body()
    data = json.loads(data.decode())
    user = request.user
    data = {
        'alias': data.get('alias'),
        'email': data.get('email'),
        'cellphone_number': data.get('cellphone_number')
    }
    user.check(data)
    await user.update_from_dict(data)
    # 记录操作日志
    await OperationLog(**{
        'op_type': C_UPGRADE,
        'op_sort': C_USER,
        'desc': '修改信息'
    }).save()
    return await UserSchema.from_tortoise_orm(user)


@action_name('修改用户分组')
@user_router.post('/iacs/user/change_permission_group')
async def change_permission_group(request: Request):
    data = await request.body()
    data = json.loads(data.decode())
    user_id = data.get('id')
    user = await User.filter(pk=user_id)
    if User.exists(id=user_id):
        user = await User.get(id=user_id)
    if len(user) > 0:
        user = user[0]
        if user.permission_group.type == PermissionGroupType.SUPER:
            raise HTTPException(HTTP_400_BAD_REQUEST, '禁止修改超级管理员权限')
    else:
        raise HTTPException(HTTP_400_BAD_REQUEST, '用户不存在')
    oper_log_user = copy.deepcopy(user)  # 记录操作前的状态
    permission_group = data.get('permission_group')
    user.permission_group = await PermissionGroup.get(pk=permission_group)
    await user.save()

    # 记录操作日志
    await OperationLog(**{
        'op_type': C_EXECUTE,
        'op_sort': C_USER,
        'desc': '修改用户分组',
        'data': {
            'before': await PermissionGroupSchema.from_tortoise_orm(oper_log_user.permission_group),
            'after': await PermissionGroupSchema.from_tortoise_orm(user.permission_group),
        }
    }).save()
    return JSONResponse({'msg': 'success'})


@action_name('获取当前用户菜单树', user_default=True)
@user_router.get('/iacs/user/my_menu_tree')
async def my_menu_tree(request: Request):
    menus = await Menu.filter(permissiongroups=request.user.permission_group_id)
    apis = await Api.filter(permissiongroups=request.user.permission_group_id)
    # api_datas = await ApiListSchema.from_queryset(Api.filter(permissiongroups=request.user.permission_group_id))
    # print('api_datas====json=======', api_datas.json(indent=4))
    # print('api_datas====dict=======', api_datas.dict())
    menu_datas = await MenuSchema.from_queryset(Menu.filter(permissiongroups=request.user.permission_group_id))
    print('menu_datas===========', menu_datas)
    print('menu_datas=====single======', await MenuSchema.from_queryset_single(Menu.first()))
    return JSONResponse()


async def get_user_menu_tree(user):
    user_root_menus = await Menu.filter(father=None).filter(permissiongroup__user__id=user.id)
    print("user_root_menus", user_root_menus)
    for menu in user_root_menus:
        print(MenuSchema.from_dict(menu, False))
        child_menus = await Menu.filter(father=menu.id)
        print(MenuSchema.to_dict(child_menus, True))

    # func = functools.partial(get_serialized_data, MenuSerializer)
    # with ThreadPoolExecutor(10) as executor:
    #     futures = executor.map(func, Menu.filter(permissiongroup__user__id=user.id))
    #     list_data = []
    #     for f in futures:
    #         list_data.append(f)
    # serializer = UserMenuTreeSerializer(instance=user_root_menus, many=True, user=user)

    # return {'list': list_data, 'tree': serializer.data}
